home *** CD-ROM | disk | FTP | other *** search
/ The Datafile PD-CD 1 Issue 2 / PDCD-1 - Issue 02.iso / _utilities / utilities / 003 / _gs / !GS / c / gdevarc < prev    next >
Text File  |  1991-12-06  |  22KB  |  722 lines

  1. /* Copyright (C) 1991 David Elworthy.  All rights reserved.
  2.    Distributed by Free Software Foundation, Inc.
  3.  
  4. This file is part of Ghostscript.
  5.  
  6. Ghostscript is distributed in the hope that it will be useful, but
  7. WITHOUT ANY WARRANTY.  No author or distributor accepts responsibility
  8. to anyone for the consequences of using it or for whether it serves any
  9. particular purpose or works at all, unless he says so in writing.  Refer
  10. to the Ghostscript General Public License for full details.
  11.  
  12. Everyone is granted permission to copy, modify and redistribute
  13. Ghostscript, but only under the conditions described in the Ghostscript
  14. General Public License.  A copy of this license is supposed to have been
  15. given to you along with Ghostscript so you can know your rights and
  16. responsibilities.  It should be in a file named COPYING.  Among other
  17. things, the copyright notice and this notice must be preserved on all
  18. copies.  */
  19.  
  20. /* gdevarc.c */
  21. /* Ghostscript driver for Acorn Archimedes (RISC OS) */
  22. /* The code here does output to a sprite, but none of the sprite display,
  23.    or the general user interface stuff.
  24.  */
  25.  
  26. /*
  27.    1.0  --  April 1991  --  First working version
  28.    2.0  --  June 1991   --  Changed for GhostScript 2.2
  29.    2.1  --  Nov  1991   --  Some code moved to gp_arc
  30.                             Split into two parts
  31.  
  32.    If the symbol GS$Options is defined, up to four floats may be read from it, setting
  33.    height and width in inches, and the x and y resolutions in dpi. The output is in the
  34.    current mode. Finally, there may be an integer, which is non zero for save only mode.
  35.    The defaults are A4, and 180 dpi. Specifying -1 for a variable gets you the default.
  36.    From version 2.2, a menu for the read and print windows allows this to be altered.
  37.  
  38.    From version 2.0 onwards, the size of the window is changed to fit the sprite, and
  39.    the sprite is redraw manually, rather than being attached to an icon.
  40.  
  41.    If the size is too large or the resolution too high, GS may fall over, probably not
  42.    cleanly.
  43. */
  44.  
  45. #include <stdlib.h>
  46. #include <string.h>
  47.  
  48. #include "wimpc.h"
  49.  
  50. #include "gx.h"
  51. #include "gsmatrix.h"                   /* for gxdevice.h */
  52. #include "gxbitmap.h"
  53. #include "gxdevice.h"
  54. /* Do all allocation directly */
  55. #include "malloc_.h"
  56.  
  57. #include "h.os"
  58. #include "bbc.h"
  59. #include "wimp.h"
  60. #include "wimpt.h"
  61. #include "win.h"
  62. #include "event.h"
  63. #include "wimpio.h"
  64. #include "colourtran.h"
  65. #include "sprite.h"
  66. #include "werr.h"
  67. #include "saveas.h"
  68.  
  69. #include "gdevarc.h"
  70. #include "gp_arc.h"
  71.  
  72. /*--- Device description --- */
  73.  
  74. /* See gxdevice.h for the definitions of the procedures. */
  75. /* Define all the procedures to start with - we can go back
  76.    to defaults for any we turn out not to use */
  77. dev_proc_open_device(arc_open);
  78. dev_proc_get_initial_matrix(arc_get_initial_matrix);
  79. dev_proc_sync_output(arc_sync_output);
  80. dev_proc_output_page(arc_output_page);
  81. dev_proc_close_device(arc_close);
  82. dev_proc_map_rgb_color(arc_map_rgb_color);
  83. dev_proc_map_color_rgb(arc_map_color_rgb);
  84. dev_proc_fill_rectangle(arc_fill_rectangle);
  85. dev_proc_tile_rectangle(arc_tile_rectangle);
  86. dev_proc_copy_mono(arc_copy_mono);
  87. dev_proc_copy_color(arc_copy_color);
  88. dev_proc_draw_line(arc_draw_line);
  89. dev_proc_fill_trapezoid(arc_fill_trapezoid);
  90. dev_proc_tile_trapezoid(arc_tile_trapezoid);
  91.  
  92. /* The device descriptor */
  93. static gx_device_procs arc_procs = {
  94.         arc_open,
  95.         arc_get_initial_matrix,
  96.         arc_sync_output,
  97.         arc_output_page,
  98.         arc_close,
  99.         arc_map_rgb_color,
  100.         arc_map_color_rgb,
  101.         arc_fill_rectangle,
  102.         arc_tile_rectangle,
  103.         arc_copy_mono,
  104.         arc_copy_color,
  105.         arc_draw_line,
  106.         arc_fill_trapezoid,
  107.         arc_tile_trapezoid
  108. };
  109.  
  110. gx_device_arc gs_arc_device = {
  111.         sizeof(gx_device_arc),
  112.         &arc_procs,
  113.         "arc",
  114. /* Width and height are actually in OS units, not pixels */
  115.         0, 0,           /* width and height in pixels */
  116.         0, 0,           /* density (pixels per inch) */
  117.         no_margins,     /* margins around imageable area (inches) */
  118.         0,              /* has_color */
  119.         255,            /* max_rgb_value */
  120.         1,              /* bits per color pixel */
  121.         0,              /* not open yet */
  122.         0,              /* mode */
  123.         1, 1,           /* OS/pixel factors */
  124.         -1,             /* Page window handle */
  125.         NULL,           /* Address of sprite area */
  126.         0,              /* Space allocated */
  127.         {0, 0},         /* Sprite id - gets filled in later */
  128.         {1, 1, 1, 1},   /* Sprite scaling */
  129.         0,              /* Are we in a 256 colour mode? */
  130.         TRUE,           /* Page closed flag */
  131.         0               /* Save only mode? */
  132. /* Palette table follows */
  133. };
  134.  
  135. /*--- Miscellaneous macros, parameters and globals ---*/
  136.  
  137. #define CheckPoint if (!gp_arc_fast) wimpc_checkpoint()
  138.  
  139. #if (0)
  140. /* Client name for allocators */
  141. char *arc_client = "GS_ARC";
  142. #endif
  143.  
  144. /* Code marked with the define AllowModeChange allows the sprite mode to be
  145.    changed. This code is not complete; I decided not to finish it because it slows
  146.    things down too much. I think all that needs doing is fixing the set_colour macro
  147. */
  148. #undef AllowModeChange
  149.  
  150. /*------------------------------- Device control code -------------------------*/
  151.  
  152. /* Open the device: do any initialization associated with making the
  153.    device instance valid.  This must be done before any output to the device.
  154.    We assume output will be in the current mode, and set the relevant parameters.
  155. */
  156. int arc_open(gx_device *dev)
  157. {
  158.     adev_needed(dev);
  159.     float width  = -1, height = -1;
  160.     float xres   = -1, yres   = -1;
  161.     int   saveonly = 0;
  162.     int   r0, r1;
  163.     int   mode;
  164.     char  opt_buffer[MAX_OPTIONS + 1];
  165.  
  166.     /* Find current mode */
  167.     mode = wimpt_mode();
  168.  
  169.     /* Read settings from options string, if it exists */
  170.     os_read_var_val("GS$Options", opt_buffer, MAX_OPTIONS);
  171.     sscanf(opt_buffer, "%f %f %f %f %d", &width, &height, &xres, &yres, &saveonly);
  172.  
  173.     arc_set_options(adev, mode, width, height, xres, yres);
  174.  
  175.     dev->has_color = (bbc_modevar(mode, bbc_NColour) > 1);
  176.     dev->bits_per_color_pixel = 1 << bbc_modevar(mode, bbc_Log2BPP);
  177.     adev->save_only = (saveonly != 0);
  178.  
  179.     /* There are no modes with more than 8bpp at present, but we should warn
  180.        in case of future expansion. Copy color won't work for more than this
  181.      */
  182.     if (dev->bits_per_color_pixel > 8)
  183.     {
  184.          printf("Warning: there are more than 8 bits per pixel\n");
  185.          printf("The current implementation may fail on some colour images\n");
  186.     }
  187.  
  188.     if (!arc_create_op(arc_dev(dev)))
  189.     {
  190.         werr(0, "Unable to create output (probably short of memory)");
  191.         return 1;
  192.     }
  193.  
  194.     /* First create the window and register event handler */
  195.     {   char title[100];
  196.         arc_set_title(adev, title);
  197.         if ((adev->page_window = w_create(title, "page", NULL)) == -1)
  198.             return 0;
  199.     }
  200.  
  201.     win_register_event_handler(adev->page_window, arc_page_event_handler, adev);
  202.     gp_arc_device_menu(arc_device_options, adev);
  203.  
  204.     /* Claim unknown events on the page window, so we can get palette changes */
  205.     win_claim_unknown_events (adev->page_window);
  206.  
  207.     /* Set the extent to the size of the sprite */
  208.     arc_set_window_extent(adev);
  209.  
  210.     /* Set the close string */
  211.     w_close_string(NULL);
  212.  
  213.     dev->is_open = 1;
  214.     return 0;
  215. }
  216.  
  217.  
  218. /* Construct the initial transformation matrix mapping user
  219.    coordinates (nominally 1/72" per unit) to device coordinates.
  220.    The Archimedes has (0,0) at the bottom left. Hence we end up with
  221.    positive xx and yy values, and zero for everything else.
  222. */
  223. void arc_get_initial_matrix(gx_device *dev, gs_matrix *mat)
  224. {
  225.     mat->xx = dev->x_pixels_per_inch/72.0;
  226.     mat->xy = 0;
  227.     mat->yx = 0;
  228.     mat->yy = dev->y_pixels_per_inch/72.0;
  229.     mat->tx = 0;
  230.     mat->ty = 0;
  231. }
  232.  
  233.  
  234. /* Synchronize the device.  If any output to the device has been
  235. buffered, send / write it now.  Note that this may be called several times
  236. in the process of constructing a page, so printer drivers should NOT
  237. implement this by printing the page.
  238. OPTIONAL
  239. */
  240. int arc_sync_output(gx_device *dev)
  241. {
  242.     /* Use this as a chance for a checkpoint */
  243.     wimpc_checkpoint();
  244.     return gx_default_sync_output(dev);
  245. }
  246.  
  247. /* Output a fully composed page to the device.  The default
  248.    definition just calls sync_output.  Printer drivers should implement this
  249.    by printing and ejecting the page.
  250. */
  251. int arc_output_page(gx_device *dev)
  252. {
  253.     adev_needed(dev);
  254.  
  255.     /* Check for save only */
  256.     if (adev->save_only)
  257.     {
  258.         saveas(file_type, "GSOutput", adev->sarea_size, arc_saver, 0, 0, (void *)adev);
  259.     }
  260.     else
  261.     {
  262.         /* Put up the window if not save only */
  263.         wimp_wstate  state;
  264.  
  265.         event_attachmenumaker(adev->page_window, arc_create_page_menu,
  266.                               arc_process_page_menu, (void *)adev);
  267.         if (wimpt_complain(wimp_get_wind_state(adev->page_window, &state)) == 0)
  268.         {
  269.             state.o.behind = -1;          /* Make sure window is opened in front */
  270.             wimpt_noerr(wimp_open_wind(&state.o));
  271.             adev->page_closed = FALSE;
  272.         }
  273.  
  274.         /* Wait until closed */
  275.         while (!adev->page_closed) event_process();
  276.         wread_fake_input("\n");
  277.     }
  278.  
  279.     return 0;
  280. }
  281.  
  282.  
  283. /* Close the device: release any associated resources.  After this,
  284.    output to the device is no longer allowed.
  285.    For notes on memory bug, see arc_create_op
  286. */
  287. int arc_close(gx_device *dev)
  288. {
  289.     adev_needed(dev);
  290.     wimpt_noerr(wimp_delete_wind(adev->page_window));
  291.     win_activedec();
  292.  
  293.     if (adev->sarea)
  294.         free((char *)(adev->sarea));
  295.     adev->sarea_size = 0;
  296.     adev->is_open = 0;
  297.     return 0;
  298. }
  299.  
  300. /* Map a RGB color to a device color.  The default algorithm simply
  301.    returns the brightness, i.e. max(red, green, blue).  The range of legal
  302.    values of the RGB arguments is given by the max_rgb_value element of the
  303.    device parameter structure.  Ghostscript assumes that for devices that
  304.    have color capability (i.e., has_color is true), map_rgb_color returns a
  305.    color index for a gray level (as opposed to a non-gray color) iff red =
  306.    green = blue.
  307. */
  308. gx_color_index arc_map_rgb_color(gx_device *dev, unsigned short red,
  309.   unsigned short green, unsigned short blue)
  310. {
  311.     adev_needed(dev);
  312.     wimp_paletteword rgb;
  313.     int colour;
  314.  
  315.     rgb.bytes.red   = red;
  316.     rgb.bytes.blue  = blue;
  317.     rgb.bytes.green = green;
  318. #ifdef AllowModeChange
  319.     rgb.bytes.gcol  = 0;
  320.     return ((gx_color_index)rgb.word);
  321. #else
  322.     colourtran_return_GCOLformode(rgb, adev->mode,
  323.                                   (wimp_paletteword *)adev->paltab, &colour);
  324.     return ((gx_color_index)colour);
  325. #endif
  326. }
  327.  
  328.  
  329. /* Map a device color code to RGB values.  The default algorithm
  330. simply sets all three elements of the result to the color.
  331. OPTIONAL
  332. */
  333. int arc_map_color_rgb(gx_device *dev, gx_color_index color,
  334.   unsigned short rgb[3])
  335. {
  336.     return gx_default_map_color_rgb(dev, color, rgb);
  337. }
  338.  
  339. /*------------------------------- Rendering code --------------------------*/
  340.  
  341. /*--- Low level functions and macros ---*/
  342.  
  343. /* Start and end output: direct output to sprite, and save context */
  344. /* This is quite inefficient */
  345. static sprite_state sstate;
  346. #define start_op sprite_outputtosprite(adev->sarea, &(adev->sprite), (int *)0, &sstate);
  347. #define end_op   sprite_restorestate(sstate);
  348.  
  349. static void arc_set_colour(gx_device_arc *dev, int col)
  350. {
  351. #ifdef AllowModeChange
  352.     wimp_paletteword pw;
  353.  
  354.     pw.word = col;
  355.     colourtran_return_GCOLformode(pw, dev->mode,
  356.                                   (wimp_paletteword *)dev->paltab, &col);
  357. #endif
  358.  
  359.     if (arc_is_col256(dev))
  360.     {
  361.         bbc_gcol(0, col >> 2);
  362.         bbc_tint(2, col &  3);
  363.     }
  364.     else
  365.         bbc_gcol(0, col);
  366. }
  367.  
  368. static void out25(char c1,int x,int y)
  369. { bbc_vdu(25); bbc_vdu(c1), bbc_vduw(x), bbc_vduw(y); }
  370.  
  371. /* Macros to adjust coordinates: pixel to OS */
  372. #define adjust_coord(x,y) x = x << adev->xeig; y = y << adev->yeig
  373. #define adjust_x(x) x = x << adev->xeig
  374.  
  375. #define fg(x,y)  sprite_writepixel(adev->sarea, &(adev->sprite), x, y, &col1)
  376. #define bg(x,y)  sprite_writepixel(adev->sarea, &(adev->sprite), x, y, &col0)
  377.  
  378. #define set_colour(d)  if (d != last_col) { if (arc_is_col256(adev)) { col1.colour = d >> 2; \
  379.  col1.tint   = (d & 3) << 6; } else col1.colour = d; last_col = d; }
  380.  
  381. /*--- Device interface routines ---*/
  382.  
  383. /* Fill a rectangle with a color.  The set of pixels filled is
  384.    {(px,py) | x <= px < x + width and y <= py < y + height}.  If width <= 0
  385.    or height <= 0, nothing should be drawn.
  386.  
  387.    We must subtract 1 from width and height, because bbc-rectangle includes
  388.    both limits.
  389. */
  390. int arc_fill_rectangle(gx_device *dev, int x, int y,
  391.   int width, int height, gx_color_index color)
  392. {
  393.     adev_needed(dev);
  394.     CheckPoint;
  395.  
  396.     if (x + width  > dev->width)  width  = dev->width  - x;
  397.     if (y + height > dev->height) height = dev->height - y;
  398.     if (width <=0 || height <= 0) return 0;
  399.     start_op
  400.     arc_set_colour(arc_dev(dev), (int)color);
  401.  
  402.     adjust_coord(x,y);
  403.     adjust_coord(width,height);
  404.  
  405.     out25(4,x,y);
  406.     out25(97,width-1,height-1);
  407.     end_op
  408.     return 0;
  409. }
  410.  
  411. /* Draw a minimum-thickness line from (x0,y0) to (x1,y1).  The
  412.    precise set of points to be filled is defined as follows.  First, if y1 <
  413.    y0, swap (x0,y0) and (x1,y1).  Then the line includes the point (x0,y0)
  414.    but not the point (x1,y1).
  415. */
  416. #define swap(a, b, temp) temp=a;a=b;b=temp;
  417. int arc_draw_line(gx_device *dev, int x0, int y0, int x1, int y1,
  418.   gx_color_index color)
  419. {
  420.     adev_needed(dev);
  421.     CheckPoint;
  422.  
  423.     if (y1 < y0)
  424.     {   int temp;
  425.         swap(x0, x1, temp);
  426.         swap(y0, y1, temp);
  427.     }
  428.  
  429.     start_op
  430.     arc_set_colour(arc_dev(dev), (int)color);
  431.  
  432.     adjust_coord(x0,y0);
  433.     adjust_coord(x1,y1);
  434.  
  435.     out25(4,x0,y0);
  436.     out25(13,x1,y1);
  437.     end_op
  438.  
  439.     return 0;
  440. }
  441.  
  442.  
  443. /* Fill a trapezoid whose corners are (x0,y0), (x0+width0,y0),
  444.    (x1,y1), and (x1+width1,y1), where y0 < y1.  If width0 < 0, width1 < 0,
  445.    width0 = width1 = 0, or y0 >= y1, nothing should be drawn; however, width0
  446.    = 0 or width1 = 0 is valid, and should result in a triangle being filled.
  447.    The points (x0+width0,y0) and (*,y1) are not included.
  448.    ??? I think this comment underspecifies the display.
  449.  
  450.    We implement this by drawing two triangles: (x0,y0):(x0+w0-1,y0):(x1,y1-1)
  451.    and (x0+w0-1,y0):(x1,y1-1):(x1+w1-1,y1-1): the limit pixels are thus excluded
  452.    (subject to rounding errors). If width1 = 0, we omit the second. If width0=0,
  453.    we plot (x0,y0):(x1,y1-1):(x1+w1-1,y1-1).
  454.  
  455.    The result is stlightly inaccurate (but so is the default routine).
  456. */
  457. int arc_fill_trapezoid(gx_device *dev, int x0, int y0, int width0,
  458.   int x1, int y1, int width1, gx_color_index color)
  459. {
  460.     adev_needed(dev);
  461.     CheckPoint;
  462.  
  463.     if (width0 < 0 || width1 < 0 || (width0 == 0 && width1 == 0) || y0 >= y1)
  464.         return 0;
  465.  
  466.     start_op
  467.     arc_set_colour(arc_dev(dev), (int)color);
  468.  
  469.     adjust_coord(x0,y0);
  470.     adjust_coord(x1,y1);
  471.     adjust_x(width0);
  472.     adjust_x(width1);
  473.  
  474.     out25(4,x0,y0);
  475.     out25(4,x1,y1-1);
  476.     if (width0 == 0)
  477.     {
  478.         /* Plot one triangle only */
  479.         out25(85,x1+width1-1,y1-1);
  480.     }
  481.     else
  482.     {
  483.         /* Plot first triangle */
  484.         out25(85,x0+width0-1,y0);
  485.         if (width1 != 0)
  486.             /* Plot second triangle */
  487.             out25(85,x1+width1-1,y1-1);
  488.     }
  489.     end_op
  490.  
  491.     return 0;
  492. }
  493.  
  494.  
  495. /* Copy a monochrome image (similar to the PostScript image
  496.    operator).  Each scan line is raster bytes wide.  Copying begins at
  497.    (data_x,0) and transfers a rectangle of the given width at height to the
  498.    device at device coordinate (x,y).  (If the transfer should start at some
  499.    non-zero y value in the data, the caller can adjust the data address by
  500.    the appropriate multiple of the raster.)  The copying operation writes
  501.    device color color0 at each 0-bit, and color1 at each 1-bit: if color0 or
  502.    color1 is gx_no_color_index, the device pixel is unaffected if the image
  503.    bit is 0 or 1 respectively.
  504.  
  505.    This operation is the workhorse for most of Ghostscript, so
  506.    implementing it efficiently is very important.
  507.  
  508.    I tried various experiments, expressing this code in other ways. But they all
  509.    take about the same time.
  510. */
  511.  
  512. int arc_copy_mono(gx_device *dev, unsigned char *data, int data_x,
  513.   int raster, int x, int y, int width, int height,
  514.   gx_color_index color0, gx_color_index color1)
  515. {
  516.     adev_needed(dev);
  517.     int base_x = x;
  518.     int h, w;
  519.     int plot0 = (color0 != gx_no_color_index);
  520.     int plot1 = (color1 != gx_no_color_index);
  521.     unsigned char *from;
  522.     int d, m, c;
  523.     int part_add, part_x;
  524.     sprite_colour col0, col1;
  525.     CheckPoint;
  526.  
  527.     /* Set fg and bg colours */
  528.     if (arc_is_col256(adev))
  529.     {
  530.       col0.colour = (int)color0 >> 2;
  531.       col0.tint   = ((int)color0 & 3) << 6;
  532.       col1.colour = (int)color1 >> 2;
  533.       col1.tint   = ((int)color1 & 3) << 6;
  534.     }
  535.     else
  536.     {
  537.         col0.colour = (int)color0;
  538.         col1.colour = (int)color1;
  539.     }
  540.  
  541.     start_op
  542.     part_add  = data_x / 8;
  543.     part_x    = 8 - (data_x % 8);
  544.  
  545.     /* Scan across each line in turn */
  546.     for (h = 0 ; h < height ; h++, data += raster)
  547.     {
  548.         x = base_x;
  549.         from = data + part_add;
  550.         w    = width;
  551.  
  552.         /* Display any partial byte, if data_x is not a multiple of 8 */
  553.         if (part_x != 8) /* Yes, that really is 8 and not 0 */
  554.         {
  555.             d = *from++;
  556.             m = 1 << part_x;
  557.  
  558.             for ( ; w > 0 && m != 0 ; w--, m = m >> 1, x++)
  559.             {
  560.                 c = d & m;
  561.                 if ((c != 0) && plot1)  /* 1 bit */
  562.                    fg(x,y);
  563.                 else if ((c == 0) && plot0) /* 0 bit */
  564.                    bg(x,y);
  565.             }
  566.         }
  567.  
  568.         /* Display remaining bytes */
  569.         while (w > 0)
  570.         {
  571.             d = *from++;
  572.  
  573.             for (m = 0x80 ; w > 0 && m != 0 ; w--, m = m >> 1, x++)
  574.             {
  575.                 /* See what bit we have */
  576.                 c = d & m;
  577.                 if ((c != 0) && plot1)  /* 1 bit */
  578.                    fg(x,y);
  579.                 else if ((c == 0) && plot0) /* 0 bit */
  580.                    bg(x,y);
  581.             }
  582.         }
  583.  
  584.         /* Next screen line */
  585.         y++;
  586.     }
  587.  
  588.     end_op
  589.     return 0;
  590. }
  591.  
  592.  
  593. /* Tile a rectangle.  Tiling consists of doing multiple copy_mono
  594. operations to fill the rectangle with copies of the tile.  The tiles are
  595. aligned with the device coordinate system, to avoid "seams".
  596.  
  597.         If color0 and color1 are both gx_no_color_index, then the tile is
  598. a color pixmap, not a bitmap: see the next section.
  599. OPTIONAL
  600. */
  601. int arc_tile_rectangle(gx_device *dev, gx_bitmap *tile,
  602.   int x, int y, int width, int height,
  603.   gx_color_index color0, gx_color_index color1,
  604.   int phase_x, int phase_y)
  605. {
  606.     return gx_default_tile_rectangle(dev,tile,x,y,width,height,color0,color1,
  607.                                      phase_x, phase_y);
  608. }
  609.  
  610.  
  611. /* Tile a trapezoid similarly.
  612. OPTIONAL
  613. */
  614. int arc_tile_trapezoid(gx_device *dev, gx_bitmap *tile,
  615.   int x0, int y0, int width0, int x1, int y1, int width1,
  616.   gx_color_index color0, gx_color_index color1,
  617.   int phase_x, int phase_y)
  618. {
  619.     return gx_default_tile_trapezoid(dev,tile,x0,y0,width0,x1,y1,width1,color0,color1,
  620.                                      phase_x, phase_y);
  621. }
  622.  
  623.  
  624. /* Copy a color image with multiple bits per pixel.  The raster is in
  625.    bytes, but x and width are in pixels, not bits.
  626.  
  627.    Do this by plotting pixels in the sprite.
  628.    This routine is untested. It will only work with less than or equal to
  629.    8 bits per pixel. However, you can't get more than that on the Archimedes
  630.    at present, using standard hardware.
  631. */
  632.  
  633. int arc_copy_color(gx_device *dev, unsigned char *data, int data_x,
  634.   int raster, int x, int y, int width, int height)
  635. {
  636.     adev_needed(dev);
  637.     int bpp = dev->bits_per_color_pixel;
  638.     int h,w;
  639.     unsigned char *from;
  640.     sprite_colour  col1;
  641.     gx_color_index last_col = gx_no_color_index;
  642.     int base_x = x;
  643.     char d;
  644.     CheckPoint;
  645.  
  646.     start_op
  647.  
  648.     /* For 8bpp, one byte = one colour, so we can optimise */
  649.     if (bpp == 8)
  650.     {
  651.         from = data;
  652.  
  653.         /* Scan across each line in turn */
  654.         for (h = 0 ; h < height ; h++, data += raster)
  655.         {
  656.             x = base_x;
  657.             for (w = width, x = base_x ; w > 0 ; w--, x++)
  658.             {
  659.                 d = *from++;
  660.                 set_colour(d);
  661.  
  662.                 fg(x,y);
  663.             }
  664.  
  665.             /* Next screen line */
  666.             y++;
  667.         }
  668.     }
  669.     else
  670.     {
  671.         int initial_mask = (bpp == 1) ? 0x80 :
  672.                            (bpp == 2) ? 0xc0 : 0xf0;
  673.         int byte_part = 8 >> (bpp-1);
  674.         int part_add, part_x, m;
  675.  
  676.         /* The following loop is similar to copy_mono */
  677.         part_add  = data_x / byte_part;
  678.         part_x    = data_x % byte_part;
  679.  
  680.         /* Scan across each line in turn */
  681.         for (h = 0 ; h < height ; h++, data += raster)
  682.         {
  683.             x = base_x;
  684.             from = data + part_add;
  685.             w    = width;
  686.  
  687.             /* Display any partial byte */
  688.             if (part_x != 0)
  689.             {
  690.                 d = *from++;
  691.                 m = initial_mask >> byte_part;
  692.  
  693.                 for ( ; w > 0 && m != 0 ; w--, m = m >> bpp, x++)
  694.                 {
  695.                     set_colour(d & m);
  696.                     fg(x,y);
  697.                 }
  698.             }
  699.         }
  700.  
  701.         /* Display remaining bytes */
  702.         while (w > 0)
  703.         {
  704.             d = *from++;
  705.  
  706.             for (m = initial_mask ; w > 0 && m != 0 ; w--, m = m >> bpp, x++)
  707.             {
  708.                 set_colour(d & m);
  709.                 fg(x,y);
  710.             }
  711.         }
  712.  
  713.         /* Next screen line */
  714.         y++;
  715.     }
  716.  
  717.     end_op
  718.  
  719.     return 0; /* No default */
  720.  
  721. }
  722.